package servlet;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import model.Share;
import model.ShareUser;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

import dao.DAO;
import dao.ShareDAO;
import dao.UtilisateurDAO;

/**
 * Servlet implementation class ManageShare
 */
@WebServlet("/ManageShare")
public class ManageShare extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ManageShare() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		//Recuperation de la requete et split des slash
		String s = request.getRequestURL().toString();
		String[] tabString = s.split("/");
		
		//Recuperation des eventuel parametres apres l'url
		String idShareOnPhone = null;
		if (tabString.length >= 7)
			idShareOnPhone = tabString[6];
		String expediteur = null;
		if (tabString.length >= 6)
			expediteur = tabString[5];

		//Recuperation des parametres
		String login = request.getParameter("login");
		String passwd = request.getParameter("passwd");
		String strsince = request.getParameter("since");

		// Si le login et le mot de passe sont correct
		if (login != null && passwd != null && idShareOnPhone != null && expediteur!=null) {

			Integer idShare = Integer.parseInt(idShareOnPhone);

			UtilisateurDAO uDAO = new UtilisateurDAO();
			int idUser = uDAO.getUserByLogin(expediteur).getIdUser();

			ShareDAO sDAO = new ShareDAO();
			Share share = sDAO.getShareById(idShare, idUser);

			// Ecriture de la requete
			PrintWriter pw = new PrintWriter(response.getOutputStream());
			pw.write("<share id=\"" + idShare + "\" expediteur=\""
					+ share.getSender().getLogin() + "\" nom=\""
					+ share.getNameShare() + "\" type=\""
					+ share.getFile().getTypeFile() + "\" date=\""
					+ share.getDateLastModificationShare() + "\">" + "\">");

			// Encodage du fichier en base 64
			File file = new File(share.getFile().getPathFile());
			byte[] data = fromFileToByte(file);

			pw.write(Base64.encode(data));
			pw.write("</share>");
			pw.close();

		} else if (login != null && passwd != null && strsince != null) {

			long since = Long.parseLong(strsince);

			UtilisateurDAO uDAO = new UtilisateurDAO();
			ShareUser user = uDAO.getUserByLogin(login);

			// Recuperation des partages reçus d'un utilisateur
			List<Share> shares = user.getReceive();

			// Ecrit la requete
			PrintWriter pw = new PrintWriter(response.getOutputStream());
			pw.write("<shares>");
			for (Share share : shares) {

				// Vérification de la date de dernière modification
				if (share.getDateLastModificationShare() > since) {
					pw.write("<share id=\"" + share.getIdShareOnPhone()
							+ "\" expediteur=\"" + share.getSender().getLogin()
							+ "\" nom=\"" + share.getNameShare() + "\" type=\""
							+ share.getFile().getTypeFile() + "\" date=\""
							+ share.getDateLastModificationShare() + "\">");
					pw.write("</share>");
				}
			}

			pw.write("</shares>");
			pw.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	@Override
	protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		String login = req.getParameter("login");
		String passwd = req.getParameter("passwd");
		Integer idShare = Integer.parseInt(req.getParameter("id"));

		// Si le login et le mot de passe sont correct
		if (login != null && passwd != null && idShare != null) {
			UtilisateurDAO uDAO = new UtilisateurDAO();
			ShareDAO sDAO = new ShareDAO();
			ShareUser user = uDAO.getUser(login, passwd);
			sDAO.deleteShare(idShare, user.getIdUser());
		}
	}

	@Override
	protected void doPut(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		String login = req.getParameter("login");
		String passwd = req.getParameter("passwd");

		// Si le login et le mot de passe sont correct
		if (login != null && passwd != null) {

			// Récupération du flux de données
			ServletInputStream streamIn = req.getInputStream();

			// Instantion d'un constructeur de document
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder parser = null;
			try {
				parser = factory.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			}

			// Création d'un document xml à partir du flux de donnée
			Document dom = null;
			try {
				dom = parser.parse(streamIn);
			} catch (SAXException e) {
				e.printStackTrace();
			}

			// Recuperation des attributs du partage
			NodeList share = dom.getElementsByTagName("share");
			Element shareElement = (Element) share.item(0);
			int id = Integer.parseInt(shareElement.getAttribute("id"));
			String nom = shareElement.getAttribute("nom");
			String type = shareElement.getAttribute("type");

			UtilisateurDAO userDao = new UtilisateurDAO();
			Set<String> destinataireLogin = new HashSet<String>();
			List<ShareUser> destinataires = new ArrayList<ShareUser>();

			// Recuperation des destinataire du partage
			NodeList destinataire = dom.getElementsByTagName("destinataire");
			if (destinataire != null && destinataire.getLength() > 0) {
				for (int i = 0; i < destinataire.getLength(); i++) {
					Element destinaireI = (Element) destinataire.item(i);
					destinataireLogin.add(destinaireI.getAttribute("login"));
					if (userDao.getUserByLogin(destinaireI
							.getAttribute("login")) != null)
						destinataires.add(userDao.getUserByLogin(destinaireI
								.getAttribute("login")));
				}
			}

			byte[] data = null;

			// Recuperation de l'image au format base64
			try {
				data = Base64.decode(shareElement.getTextContent());
			} catch (Base64DecodingException | DOMException e) {
				e.printStackTrace();
			}

			int indice = type.lastIndexOf("/") + 1;
			String typeFile = type.substring(indice, type.length());
			String pathFile = createFIle(data, nom, typeFile);

			ShareDAO shareDAO = new ShareDAO();
			shareDAO.addShare(id, userDao.getUser(login, passwd), nom,
					destinataires, type, pathFile);

		}

	}

	// Méthode qui crée un fichier à partir d'un tableau de byte
	private String createFIle(byte[] data, String name, String type) {

		java.io.File file = new File("./" + name + "." + type);
		file.setWritable(true, false);
		file.setReadable(true, false);

		try {
			file.createNewFile();
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		try {
			// convert array of bytes into file
			FileOutputStream fileOuputStream = new FileOutputStream("./" + name
					+ "." + type);
			fileOuputStream.write(data);
			fileOuputStream.close();

			System.out.println("Done");
		} catch (Exception e) {
			e.printStackTrace();
		}

		return "./" + name + "." + type;
	}

	// Méthode qui renvoie le tableau de byte d'un fichier
	@SuppressWarnings("resource")
	private byte[] fromFileToByte(File file) {

		int len;
		int size = 1024;
		byte[] buf;

		FileInputStream is = null;
		try {
			is = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		buf = new byte[size];
		try {
			while ((len = is.read(buf, 0, size)) != -1)
				bos.write(buf, 0, len);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		buf = bos.toByteArray();
		return buf;
	}
}
